/**
* 实现生成字节码
**/
#define luac_c
#define LUA_CORE

#include "lprefix.h"

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "lua.h"
#include "lauxlib.h"

#include "lobject.h"
#include "lstate.h"
#include "lundump.h"

#define PROGNAME	"luac"		/* default program name */

#define FUNCTION "(function()end)();"
#define toproto(L,i) getproto(L->top+(i))

static unsigned char *s = NULL;
static unsigned int slen = 512;
static unsigned int uselen = 0;


void luac_free()
{
    free(s);
    s=NULL;
    slen=512;
    uselen=0;
}

static void luacs_fatal(const char* message, unsigned char **outstr_p, unsigned int *outlen_p)
{
    luac_free();
    if (NULL == message) return;

    uselen=strlen(message);
    while (slen < uselen) slen=slen*2;
    s=(unsigned char *)malloc(slen*sizeof(unsigned char));
    sprintf((char *)s,"%s",message);
    *outstr_p=s;
    *outlen_p=uselen;
}

static const char* luacs_reader(lua_State *L, void *ud, size_t *size)
{
    UNUSED(L);
    if ((*(int*)ud)--)
    {
        *size=sizeof(FUNCTION)-1;
        return FUNCTION;
    }
    else
    {
        *size=0;
        return NULL;
    }
}

static const Proto* luacs_combine(lua_State* L, int n)
{
    if (n==1)
        return toproto(L,-1);
    else
    {
        Proto* f;
        int i=n;
        if (lua_load(L,luacs_reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) {
            luacs_fatal(lua_tostring(L,-1), &s, &uselen);
            return NULL;
        }
        f=toproto(L,-1);
        for (i=0; i<n; i++)
        {
            f->p[i]=toproto(L,i-n-1);
            if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
        }
        f->sizelineinfo=0;
        return f;
    }
}

static int luacs_writer(lua_State* L, const void* p, size_t size, void* u)
{
    UNUSED(L);
    UNUSED(u);
    if (size<=0) return 1;
    if (s==NULL) s=(unsigned char *)malloc(slen*sizeof(unsigned char));
    while (uselen+size>=slen) {
        slen=slen*2;
        s = (unsigned char *)realloc(s,slen*sizeof(unsigned char));
    }
    memcpy(s+uselen,p,size);
    uselen += size;
    return 0;
}

/**
* 生成lua字节码
* 代码参照luac.c中写的
**/
int luac(int argc, char* argv[], unsigned char **outstr_p, unsigned int *outlen_p)
{
    lua_State* L;
    if (NULL == (L = luaL_newstate())) {
        luacs_fatal("not enough memory for state", outstr_p, outlen_p);
        return -1;
    }

    if (!lua_checkstack(L,argc)) {
        luacs_fatal("too many input files", outstr_p, outlen_p);
        return -1;
    }

    int i;
    for (i=0; i<argc; i++) {
        if (luaL_loadstring(L,argv[i])!=LUA_OK) {
            luacs_fatal(lua_tostring(L,-1), outstr_p, outlen_p);
            return -1;
        }
    }

    const Proto* f=luacs_combine(L,argc);
    if (NULL == f) {
      return -1;
    }
    lua_lock(L);
    luaU_dump(L,f,luacs_writer,NULL,1);
    lua_unlock(L);
    lua_close(L);
    *outstr_p=s;
    *outlen_p=uselen;
    return 0;
}
